/*
 * Copyright 2005 Sandbridge Technologies, Inc. All rights reserved.
 */

#ifndef armxdsp_h_
#define armxdsp_h_

#include "dspmap.h"

#define DSP_CORE0       0
#define DSP_CORE1       1
#define DSP_CORE2       2
/*
 * The minimum slot size in bytes.
 */
#define ARMXDSP_MIN_SLOT_SIZE 16

/*
 * The maximum number of slots per message queue. The actual number of slots
 * may be specified through the config parameter to armxdsp_mq_init_* functions.
 */
#define ARMXDSP_MAX_SLOT_COUNT 32

/*
 * A set of slots containing all slots
 */
#define ARMXDSP_ALL_SLOTS (~0U)

/*
 * This macro computes the size of the message queue header in bytes;
 * the size of the header depends on the number of slots;
 * the following assertion is always true:
 *      ARMXDSP_MQ_SIZE(1) == sizeof(armxdsp_mq_t)
 */
#define ARMXDSP_MQ_SIZE(slot_count) \
    (4*4+(slot_count)*(8*4))


/*
 * The actual size of the slot that can hold the specifyd number of bytes;
 * the result of this macro is always a multiple of 4;
 */
#define ARMXDSP_SLOT_SIZE(size) \
    (((size)+3)&~3)

/*
 * Computes the smallest size of a slot capable of holding 'count' messages
 * of 'size' bytes each;
 */
#define ARMXDSP_OPTIMAL_SLOT_SIZE(msg_count,msg_size) \
    ARMXDSP_SLOT_SIZE((msg_count)*(4+(((msg_size)+3)&~3)))

/*
 * The error codes returned by the API functions
 */
#define ARMXDSP_EAGAIN    (-1)
#define ARMXDSP_EINVAL    (-2)
#define ARMXDSP_ENOTSUP   (-3)
#define ARMXDSP_EINIT     (-4)
#define ARMXDSP_ECONFIG   (-5)
#define ARMXDSP_EDSP      (-6)
#define ARMXDSP_ESLOT     (-7)
#define ARMXDSP_ESIZE     (-8)

/*
 * Message queue configuration;
 * the configuration parameters are used by armxdsp_init_* functions.
 */
typedef struct armxdsp_mq_config {
    /* the number of slots */
    uint32_t slot_count;
    /* the size of each slot in bytes */
    uint32_t slot_size[ARMXDSP_MAX_SLOT_COUNT];
} armxdsp_mq_config_t;

/*
 * Message queue header;
 * this data structure is used internally and should not be used by applications;
 * the total number of bytes occupied by a message queue can be computed
 * as follows:
 *     ARMXDSP_MQ_SIZE(N)
 *     + ARMXDSP_SLOT_SIZE(size_1)
 *     + ...
 *     + ARMXDSP_SLOT_SIZE(size_N)
 * where N is the number of slots in the queue; size_[1,N] is the size of
 * each slot;
 */
typedef struct armxdsp_mq armxdsp_mq_t;

/*
 * Message queue slot header;
 * this data structure is used internally and should not be used by applications.
 */
typedef struct armxdsp_mq_slot armxdsp_mq_slot_t;

/*
 * MESSAGE QUEUE INFORMATION FUNCTIONS
 */

/*
 * MESSAGE QUEUE CLIENT FUNCTIONS
 */

/*
 * MESSAGE QUEUE OWNER FUNCTIONS
 */

/*
 * MESSAGE SENDER FUNCTIONS
 */

/*
 * This data structure contains information describing the state
 * of message sending operation currently in progress; it is
 * initialized by the 'armxdsp_send_begin' and destroyed by
 * 'armxdsp_send_end';
 */
typedef struct armxdsp_sender {
    /* DSP logical core number */
    int dsp;
    /* destination queue slot */
    int slot;
    /* size of the message data */
    uint32_t size;
    /* pointer to the message data */
    void* data;
    /* the following fields are for internal use only */
    uint32_t used_size;
} armxdsp_sender_t;

/*
 * Initiates message transmission; when this function succeeds it returns
 * 0 and sets 'sender->data' to point to the buffer to be filled with
 * the message data; once the data is stored to the buffer, a call to
 * 'armxdsp_send_end' sends the message; the function blocks until 'size'
 * bytes are available in the slot 'slot' of outgoing message queue
 * associated with DSP logical core 'dsp';
 *
 * if successfull this function returns 0, otherwise it returns one of
 * the ARMXDSP_E* error codes;
 */
int armxdsp_send_begin(armxdsp_sender_t* sender, int dsp, int slot, uint32_t size);

/*
 * Non-blocking version of 'armxdsp_send_begin'; if there is enough free space
 * in the outgoing message queue, returns 0 and sets 'sender->data' to point to
 * the buffer to be filled with the message data; otherwise returns
 * immediately with ARMXDSP_EAGAIN error code; once the data is stored to the
 * buffer, a call to 'armxdsp_send_end' sends the message;
 *
 * if successfull this function returns 0, otherwise it returns one of
 * the ARMXDSP_E* error codes;
 */
int armxdsp_send_begin_nb(armxdsp_sender_t* sender, int dsp, int slot, uint32_t size);

/*
 * Finalizes message transmission initiated by a previous call to
 * 'armxdsp_send_begin' or 'armxdsp_send_begin_nb';
 */
void armxdsp_send_end(armxdsp_sender_t* sender);

/*
 * MESSAGE RECEIVER FUNCTIONS
 */

/*
 * This data structure contains information describing the state
 * of message reception currently in progress; it is
 * initialized by the 'armxdsp_receive_begin' and destroyed by
 * 'armxdsp_receive_end';
 */
typedef struct armxdsp_receiver {
    /* DSP logical core number */
    int dsp;
    /* queue slot that hold the message being received */
    int slot;
    /* size of the message data */
    uint32_t size;
    /* pointer to the message data */
    void* data;
    /* the following fields are for internal use only */
    uint32_t used_size;
} armxdsp_receiver_t;

/*
 * Initiates message reception; when this function succeeds it returns
 * 0 and sets 'receiver->data' to point to a buffer that contains
 * the message data; once the data is retrieved from the buffer, call
 * to 'armxdsp_receive_end' removes the message from the queue; the function
 * blocks until a message is available in any of the slots specified by the
 * 'slotmask';
 *
 * if successfull this function returns 0, otherwise it returns one of
 * the ARMXDSP_E* error codes;
 */
int armxdsp_receive_begin(armxdsp_receiver_t* receiver, int dsp, uint32_t slotmask);

/*
 * Non-blocking version of 'armxdsp_receive_begin'; returns ARMXDSP_EAGAIN if
 * there are no messages in the slots specified by 'slotmask' in incoming message
 * queue associated with DSP logical core 'dsp';
 *
 * if successfull this function returns 0, otherwise it returns one of
 * the ARMXDSP_E* error codes;
 */
int armxdsp_receive_begin_nb(armxdsp_receiver_t* receiver, int dsp, uint32_t slotmask);

/*
 * Removes the message received by the previous call
 * to 'armxdsp_receive_begin' or 'armxdsp_receive_begin_nb' from
 * the queue;
 */
void armxdsp_receive_end(armxdsp_receiver_t* receiver);

/*
 * Message reception notification handler;
 */
typedef void (*armxdsp_receive_handler_t)(int dsp, void* param);

#if defined(ARMXDSP_LOOPBACK) || defined(__SANDBLASTER__)
int armxdsp_open_queues(void);

int armxdsp_send_begin_dsp(armxdsp_sender_t* sender, int dsp, int slot, uint32_t size);
int armxdsp_send_begin_nb_dsp(armxdsp_sender_t* sender, int dsp, int slot, uint32_t size);
void armxdsp_send_end_dsp(armxdsp_sender_t* sender);
int armxdsp_receive_begin_dsp(armxdsp_receiver_t* receiver, int dsp, uint32_t slotmask);
int armxdsp_receive_begin_nb_dsp(armxdsp_receiver_t* receiver, int dsp, uint32_t slotmask);
void armxdsp_receive_end_dsp(armxdsp_receiver_t* receiver);
#endif

#endif

/* vim:se ts=4 sw=4: */
